package lj.netty.channel;

import cn.hutool.core.lang.Opt;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import lj.netty.ComNetty;
import lj.netty.bean.LJNettyBo;
import lj.netty.listen.LJCNettyListen;
import lj.netty.tool.LJTNetty;
import lombok.Data;
import ntd.util.UtilCatch;

@ChannelHandler.Sharable
@Data
public class ChannelHandlerCommon extends ChannelInboundHandlerAdapter {

    private ComNetty comNetty;
    /**
     * 消息监听器
     */
    private LJCNettyListen ljcNettyListen;

    public ChannelHandlerCommon(ComNetty comNetty, LJCNettyListen ljcNettyListen) {
        this.comNetty = comNetty;
        this.ljcNettyListen = ljcNettyListen;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf byteBuf = (ByteBuf) msg;
        try {
            byte[] bytes = ByteBufUtil.getBytes(byteBuf);
            if (bytes.length < 1) {
                return;
            }
//            StaticLog.info("tcp收到数据[{}]", JSONUtil.toJsonStr(ArrayUtil.sub(bytes, 0, 200)));

            ctx.fireChannelRead(msg);
            LJNettyBo ljNettyBo = LJNettyBo.transform(ctx.channel());
            ljNettyBo.setBytes(bytes);
            ThreadUtil.execAsync(() -> {
                Opt.ofNullable(ljcNettyListen).ifPresent(comNettyListen1 -> comNettyListen1.onMsg(ljNettyBo));
            });
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            release(byteBuf);
        }
    }

    private static void release(ByteBuf byteBuf) {
        int index = byteBuf.refCnt();
        if (index > 0) {
            byteBuf.release(index);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        try {
            LJTNetty.addChannel(ctx.channel());
            ThreadUtil.execAsync(() -> {
                Opt.ofNullable(ljcNettyListen).ifPresent(comNettyListen1 -> comNettyListen1.onInit(LJNettyBo.transform(ctx.channel())));
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void channelInactive(final ChannelHandlerContext ctx) {
        try {
            LJTNetty.removeChannel(ctx.channel());
            ThreadUtil.execAsync(() -> {
                Opt.ofNullable(ljcNettyListen).ifPresent(comNettyListen1 -> comNettyListen1.onClose(LJNettyBo.transform(ctx.channel())));
            });
            StaticLog.info("netty 连接断开:" + ctx.channel().remoteAddress());
            startRestConn(ctx);
//            ToolNetty.removeChannel(ctx.channel());
//            onClose(ComNettyBo.transform(ctx.channel()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void startRestConn(ChannelHandlerContext ctx) {
        for (int i = 0; i < 10; i++) {
            if (comNetty.conn()) {
                StaticLog.info("netty 重连成功...");
                return;
            }
            StaticLog.info("netty 重连失败:" + ctx.channel().remoteAddress());
            ThreadUtil.sleep(1000 * 60);
            if (ctx.channel().isActive()) {
                StaticLog.info("netty 重连失败 - 监测成功:" + ctx.channel().remoteAddress());
                return;
            }
        }
    }

    @Override
    public void channelUnregistered(final ChannelHandlerContext ctx) {
        try {
//            startRestConn(ctx);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        if (ctx.channel().isActive()) ctx.close();
        StaticLog.error(cause);
    }

}
